import 'dart:convert';
import 'dart:io';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:path/path.dart' as path;
import '../serve/file_serve.dart';

class DifyKnowledgeDatabase {
  late Map<String, dynamic> config;
  late Map<String, String> documentsId;
  late String difyUrl;
  late String difyApiKey;
  late String indexingTechnique;
  String? datasetId;
  late String embeddingModel;
  late String embeddingModelProvider;
  late Map<String, dynamic> retrievalModel;
  late Map<String, dynamic> processRule;
  late String configPath;
  late http.Client client;
  late FileServe _fileServe;
  bool _isInitialized = false;

  // 私有构造函数
  DifyKnowledgeDatabase._() {
    _fileServe = FileServe();
    client = http.Client();
    // 初始化默认值，避免null错误
    config = {};
    documentsId = {};
    difyUrl = "https://api.dify.ai/v1"; // 默认值
    difyApiKey = "dummy-api-key"; // 默认值
    indexingTechnique = "high_quality"; // 默认值
    embeddingModel = "text-embedding-ada-002"; // 默认值
    embeddingModelProvider = "openai"; // 默认值
    retrievalModel = {
      "search_method": "semantic_search",
      "reranking_model": "default",
      "reranking_enable": true,
      "top_k": 2,
      "score_threshold": 0.5
    }; // 默认值
    processRule = {
      "mode": "custom",
      "rules": {
        "pre_processing_rules": [
          {"id": "remove_extra_spaces", "enabled": true},
          {"id": "remove_urls_emails", "enabled": false}
        ],
        "chunk_size": 500,
        "chunk_overlap": 50,
        "separators": ["\n\n", "\n", " ", ""]
      }
    }; // 默认值
    configPath = "";
  }
  
  // 静态工厂方法，用于创建并初始化实例
  static Future<DifyKnowledgeDatabase> create() async {
    final instance = DifyKnowledgeDatabase._();
    try {
      await instance._initialize();
    } catch (e) {
      print('DifyKnowledgeDatabase初始化失败: $e');
      // 即使初始化失败，也返回已创建的实例
    }
    return instance;
  }
  
  Future<void> _initialize() async {
    if (_isInitialized) return;
    
    try {
      await _fileServe.initialize();
      configPath = path.join(_fileServe.returnConfigPath(), 'dify_dataset.json');
      await _readConfig();
      await _readFileId();
      
      _isInitialized = true;
    } catch (e) {
      print('DifyKnowledgeDatabase初始化错误: $e');
      // 不抛出异常，让应用继续运行
    }
  }

  // 确保初始化完成
  Future<void> ensureInitialized() async {
    if (!_isInitialized) {
      try {
        await _initialize();
      } catch (e) {
        print('确保初始化时出错: $e');
        // 继续使用默认值
      }
    }
  }

  // 读取文档ID映射
  Future<void> _readFileId() async {
    try {
      Map<String, dynamic> mappings = await _fileServe.getDocIdMappings();
      documentsId = Map<String, String>.from(mappings);
    } catch (e) {
      print('读取文档ID时出错: $e');
      documentsId = {};
    }
  }

  // 更新文档ID映射
  Future<bool> _updateDocIdMapping(String docId, String filePath) async {
    try {
      // 更新内存中的映射
      documentsId[docId] = filePath;
      // 更新文件中的映射
      return await _fileServe.updateDocIdMapping(docId, filePath);
    } catch (e) {
      print('更新文档ID映射时出错: $e');
      return false;
    }
  }

  Future<void> _readConfig() async {
    try {
      // 使用FileServe获取Dify配置
      config = await _fileServe.getConfig('Dify');
      
      difyUrl = config["dify_base_url"];
      difyApiKey = config["dify_dataset_api"];
      indexingTechnique = config["indexing_technique"];
      datasetId = config["dataset_id"];
      embeddingModel = config["embedding_model"];
      embeddingModelProvider = config["embedding_model_provider"];
      retrievalModel = config["retrieval_model"];
      processRule = config["other_config"]["process_rule"];
    } catch (e) {
      print('读取Dify配置时出错: $e');
      rethrow;
    }
  }

  // 更新配置文件的方法
  Future<bool> updateConfig() async {
    try {
      return await _fileServe.changeDifyDatasetConfig(config);
    } catch (e) {
      print('更新Dify配置时出错: $e');
      return false;
    }
  }

  Future<Map<String, dynamic>?> createEmptyDataset(String datasetName, String datasetDescription) async {
    await ensureInitialized();
    
    final payload = {
      "name": datasetName,
      "description": datasetDescription,
      "permissions": "only_me"
    };

    try {
      final response = await client.post(
        Uri.parse("$difyUrl/datasets"),
        headers: {
          "Authorization": "Bearer $difyApiKey",
          "Content-Type": "application/json",
        },
        body: jsonEncode(payload),
      );

      if (response.statusCode == 200) {
        final responseData = jsonDecode(response.body);
        datasetId = responseData["id"];
        config["dataset_id"] = datasetId;
        
        // 使用FileServe更新配置
        await updateConfig();
        
        return responseData;
      } else {
        print("Error creating dataset: ${response.body}");
        return null;
      }
    } catch (e) {
      print("Error creating dataset: $e");
      return null;
    }
  }

  Future<Map<String, dynamic>?> createDataset(String datasetName, String datasetDescription, String mdPath) async {
    await ensureInitialized();
    
    final emptyDatasetResponse = await createEmptyDataset(datasetName, datasetDescription);
    if (emptyDatasetResponse == null) return null;

    final file = File(mdPath);
    final fileContent = await file.readAsBytes();
    final fileName = path.basename(mdPath);

    final data = {
      "indexing_technique": indexingTechnique,
      "doc_form": "text_model",
      "process_rule": processRule,
      "retrieval_model": retrievalModel,
      "embedding_model": embeddingModel,
      "embedding_model_provider": embeddingModelProvider
    };

    final request = http.MultipartRequest(
      'POST',
      Uri.parse("$difyUrl/datasets/$datasetId/document/create-by-file"),
    );

    request.headers["Authorization"] = "Bearer $difyApiKey";
    request.files.add(
      http.MultipartFile.fromBytes(
        'file',
        fileContent,
        filename: fileName,
      ),
    );
    request.fields['data'] = jsonEncode(data);

    try {
      final response = await request.send();
      final responseBody = await response.stream.bytesToString();
      
      if (response.statusCode == 200) {
        final responseData = jsonDecode(responseBody);
        final docId = responseData["document"]["id"];
        // 更新文档ID映射
        await _updateDocIdMapping(docId, mdPath);
        return responseData;
      } else {
        print("Error creating dataset: $responseBody");
        return null;
      }
    } catch (e) {
      print("Error creating dataset: $e");
      return null;
    }
  }

  Future<Map<String, dynamic>> getDocEmbedding(String batch) async {
    await ensureInitialized();
    
    final response = await client.get(
      Uri.parse("$difyUrl/datasets/$datasetId/documents/$batch/indexing-status"),
      headers: {"Authorization": "Bearer $difyApiKey"},
    );
    return jsonDecode(response.body);
  }

  Future<Map<String, dynamic>> getDatasetsList() async {
    await ensureInitialized();
    
    final response = await client.get(
      Uri.parse("$difyUrl/datasets?limit=100"),
      headers: {"Authorization": "Bearer $difyApiKey"},
    );
    return jsonDecode(response.body);
  }

  Future<String> deleteDataset() async {
    await ensureInitialized();
    
    final response = await client.delete(
      Uri.parse("$difyUrl/datasets/$datasetId"),
      headers: {"Authorization": "Bearer $difyApiKey"},
    );
    return response.body;
  }

  Future<List<Map<String, dynamic>>> query(String queryText) async {
    await ensureInitialized();
    
    try {
      // 设置超时时间
      final client = http.Client();
      final request = http.Request('POST', Uri.parse("$difyUrl/datasets/$datasetId/retrieve"));
      request.headers.addAll({
        "Authorization": "Bearer $difyApiKey",
        "Content-Type": "application/json",
      });
      request.body = jsonEncode({"query": queryText});
      
      // 使用超时机制
      final responseStream = await client.send(request).timeout(
        Duration(seconds: 10),
        onTimeout: () {
          client.close();
          throw TimeoutException('知识库查询超时');
        }
      );
      
      final response = await http.Response.fromStream(responseStream);
      
      if (response.statusCode >= 400) {
        print("知识库查询失败: ${response.statusCode} - ${response.body}");
        return [];
      }
      
      final responseData = jsonDecode(response.body);
      final List<Map<String, dynamic>> answers = [];

      for (var segment in responseData['records']) {
        answers.add({
          "document_id": segment['segment']["document_id"],
          "score": segment['score'],
          "content": segment['segment']["content"]
        });
      }

      return answers;
    } catch (e) {
      print("知识库查询出错: $e");
      return []; // 出错时返回空列表
    }
  }

  Future<Map<String, dynamic>?> addDocuments(String documentPath) async {
    await ensureInitialized();
    
    if (datasetId == null || datasetId!.isEmpty) {
      print("错误: 数据集ID为空，无法添加文档");
      return {
        "success": false,
        "message": "数据集ID为空",
        "document": {"id": "error_no_dataset"}
      };
    }
    
    final file = File(documentPath);
    if (!await file.exists()) {
      print("错误: 文件不存在: $documentPath");
      return {
        "success": false,
        "message": "文件不存在",
        "document": {"id": "error_file_not_found"}
      };
    }
    
    try {
      final fileContent = await file.readAsBytes();
      final fileName = path.basename(documentPath);

      final data = {
        "indexing_technique": indexingTechnique,
        "doc_form": "text_model",
        "process_rule": processRule
      };

      final request = http.MultipartRequest(
        'POST',
        Uri.parse("$difyUrl/datasets/$datasetId/document/create-by-file"),
      );

      request.headers["Authorization"] = "Bearer $difyApiKey";
      request.files.add(
        http.MultipartFile.fromBytes(
          'file',
          fileContent,
          filename: fileName,
        ),
      );
      request.fields['data'] = jsonEncode(data);

      final response = await request.send();
      final responseBody = await response.stream.bytesToString();
      
      if (response.statusCode == 200) {
        final responseData = jsonDecode(responseBody);
        final docId = responseData["document"]["id"];
        print("成功添加文档到Dify: $docId");
        
        // 更新文档ID映射
        await _updateDocIdMapping(docId, documentPath);
        return responseData;
      } else {
        print("添加文档到Dify失败: $responseBody");
        return {
          "success": false,
          "message": "API错误: ${response.statusCode}",
          "document": {"id": "error_api_${response.statusCode}"}
        };
      }
    } catch (e) {
      print("添加文档到Dify时发生异常: $e");
      return {
        "success": false,
        "message": "发生异常: $e",
        "document": {"id": "error_exception"}
      };
    }
  }

  // 通过文档ID获取文件路径
  Future<String?> getDocumentPath(String documentId) async {
    if (documentsId.containsKey(documentId)) {
      return documentsId[documentId];
    } else {
      // 如果内存中没有，尝试从文件读取
      return await _fileServe.getFilePathByDocId(documentId);
    }
  }

  Future<Map<String, dynamic>?> renewDocuments(String documentId, String documentPath) async {
    await ensureInitialized();
    
    final file = File(documentPath);
    final fileContent = await file.readAsBytes();
    final fileName = path.basename(documentPath);

    final data = {
      "indexing_technique": indexingTechnique,
      "doc_form": "text_model",
      "process_rule": processRule
    };

    final request = http.MultipartRequest(
      'POST',
      Uri.parse("$difyUrl/datasets/$datasetId/documents/$documentId/update-by-file"),
    );

    request.headers["Authorization"] = "Bearer $difyApiKey";
    request.files.add(
      http.MultipartFile.fromBytes(
        'file',
        fileContent,
        filename: fileName,
      ),
    );
    request.fields['data'] = jsonEncode(data);

    try {
      final response = await request.send();
      final responseBody = await response.stream.bytesToString();
      
      if (response.statusCode == 200) {
        // 更新文档ID映射
        await _updateDocIdMapping(documentId, documentPath);
        return jsonDecode(responseBody);
      } else {
        print("Error renewing document: $responseBody");
        return null;
      }
    } catch (e) {
      print("Error renewing document: $e");
      return null;
    }
  }
  
  // 删除文档
  Future<Map<String, dynamic>> deleteDocument(String documentId) async {
    await ensureInitialized();
    
    try {
      print('正在删除文档: ID=$documentId');
      
      if (datasetId == null || datasetId!.isEmpty) {
        print('错误: 知识库ID为空');
        return {"result": "error", "message": "知识库ID为空"};
      }
      
      final response = await client.delete(
        Uri.parse("$difyUrl/datasets/$datasetId/documents/$documentId"),
        headers: {"Authorization": "Bearer $difyApiKey"},
      );
      
      print('删除文档API响应状态码: ${response.statusCode}');
      
      if (response.statusCode == 200) {
        // 解析响应
        final Map<String, dynamic> responseBody = jsonDecode(response.body);
        print('成功删除文档: ${response.body}');
        
        // 删除文档ID映射
        await _fileServe.removeDocIdMapping(documentId);
        // 从内存中移除
        documentsId.remove(documentId);
        
        return responseBody;
      } else {
        print("删除文档失败: ${response.statusCode} - ${response.body}");
        return {"result": "error", "message": "API响应错误: ${response.statusCode}", "response": response.body};
      }
    } catch (e) {
      print("删除文档时发生异常: $e");
      return {"result": "error", "message": "发生异常: $e"};
    }
  }

  void dispose() {
    client.close();
  }
}
